/*
 * The gTree filesystem
 *
 * Copyright (c) 2019 DengGuozu
 *
 * Licensed under the Apache License, Version 1.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
 
#include "gfs_api.h"

#ifdef GTREE_FILE_COURCE



//========================================================================================================

typedef struct
{
	u16	head;	//块头:[FFFF] 已经察除，[48||84] 坏块，[EEEE] 引导数据，[DDDD] 使用数据
	u16	pgSize;	//块大小
	int count;
}eFlashCheck;


typedef struct
{
	eFlashCheck f;
	u32 data[0];
}DfBalancedAccountUnit;

int BalancedAccountInit(DfBalancedRecord *pAccount,u16 BlockStart,u16 BlockNum,u16 aSize)
{
	u32 Addr;
	eFlashCheck head1,head2;
	if((aSize+sizeof(eFlashCheck)) > GFS_BLOCK_SIZE) return -1;
	if(aSize&0x03) return -2;
	pAccount->pgSize = ((aSize+sizeof(eFlashCheck))+(GFS_PAGE_SIZE-1))&(~(GFS_PAGE_SIZE-1));
	pAccount->PageNum = GFS_BLOCK_SIZE / pAccount->pgSize;
	pAccount->PageMax = BlockNum * pAccount->PageNum;
	if(pAccount->PageMax < 2) return -3;
	pAccount->parLen = aSize;
	pAccount->blockStart = BlockStart;
	if(BlockStart == GFS_BASIC_NULL)
		return GFS_BASIC_NULL;
	head1.head = GFS_BASIC_NULL;
	for(pAccount->PageIndex=0;pAccount->PageIndex < pAccount->PageMax ;pAccount->PageIndex++) {
		Addr = GFS_BLOCK_SIZE*(pAccount->blockStart+(pAccount->PageIndex / pAccount->PageNum))+ \
				pAccount->pgSize * (pAccount->PageIndex % pAccount->PageNum);
		SPI_Flash_Read(Addr,(u32*)&head2,sizeof(eFlashCheck));
		if(head2.head == GFS_BASIC_DATA && head2.pgSize == pAccount->pgSize) {
			if(head1.head == GFS_BASIC_NULL || (head2.count - head1.count) > 0) {
				head1.count = head2.count;
				head1.head = GFS_BASIC_DATA;
				head1.pgSize = pAccount->PageIndex;	//借用pgSize 存 PageIndex
				continue;
			}
			break;
		}
	}
	if(head1.head == GFS_BASIC_DATA) {
		pAccount->count = head1.count;
		pAccount->PageIndex = head1.pgSize;
		LG("Ok->PageIndex[%d]->count[%d]pgSize[%d]\r\n",pAccount->PageIndex,pAccount->count,pAccount->pgSize);
		return pAccount->parLen;
	}
	return 0;
}

int BalancedAccountRead(DfBalancedRecord *pAccount,int PreviousIndex,void* pBuff)
{
	u32 Addr;
	int index;
	u32 buffdata[GFS_BLOCK_SIZE/4];
	DfBalancedAccountUnit *pUnit;
	if(pAccount->PageMax == 0) return -2;
	if(PreviousIndex > pAccount->PageMax) return -3;
	index = (int)pAccount->PageIndex - PreviousIndex;
	if(index < 0) index += pAccount->PageMax;
	Addr=GFS_BLOCK_SIZE*(pAccount->blockStart+(index / pAccount->PageNum))\
			+ pAccount->pgSize*(index % pAccount->PageNum);
	SPI_Flash_Read(Addr,buffdata,sizeof(eFlashCheck)+DfGetBeiSu(pAccount->parLen,4));
	pUnit = (DfBalancedAccountUnit *)buffdata;
	if(pUnit->f.head == GFS_BASIC_DATA && pUnit->f.pgSize == pAccount->pgSize) {
		memcpy(pBuff,pUnit->data,pAccount->parLen);
		return pAccount->parLen;
	}
	return 0;
}

int BalancedAccountSave(DfBalancedRecord *pAccount,void* pBuff)
{
	u32 Addr;
	u16 lenPar,Maxlen;
	u32 buffdata[GFS_BLOCK_SIZE/4];
	DfBalancedAccountUnit tCheck;
	DfBalancedAccountUnit *pUnit;
	if(pAccount->PageMax == 0) return -2;
	lenPar = sizeof(pUnit->f) + pAccount->parLen;
	pUnit =(DfBalancedAccountUnit *)buffdata;
	pUnit->f.head = GFS_BASIC_DATA;
	pUnit->f.pgSize = pAccount->pgSize;
	Maxlen = DfGetBeiSu(lenPar,4);
	//pCheck = ((u8*)pUnit)+Maxlen;	//复用地址
	//LG("BalancedAccountSave lenPar[%d]Maxlen[%d]",lenPar,Maxlen);
	while(1) {
		pAccount->count++;
		pUnit->f.count = pAccount->count;
		pAccount->PageIndex++;
		if(pAccount->PageIndex >= pAccount->PageMax)
			pAccount->PageIndex=0;
	
		Addr=GFS_BLOCK_SIZE*(pAccount->blockStart+(pAccount->PageIndex / pAccount->PageNum)) + \
			pAccount->pgSize * (pAccount->PageIndex % pAccount->PageNum);
		if(!(pAccount->PageIndex % pAccount->PageNum)) {
			SPI_Flash_ERASE_SECTOR(Addr);
		}
		//TRACE("PageIndex[%d] Addr[%x]\r\n",pAccount->PageIndex,Addr);
		memcpy(pUnit->data,pBuff,pAccount->parLen);
		int wlen=SPI_Flash_Write(Addr,pUnit,Maxlen);
		int rlen=SPI_Flash_Read(Addr,&tCheck,sizeof(tCheck));
		if(memcmp_u32((u32*)pUnit,(u32*)&tCheck,sizeof(tCheck)/4) == 0) {
			SPI_Flash_Read(Addr+sizeof(tCheck),pUnit->data,pAccount->parLen);
			if(memcmp(pUnit->data,pBuff,pAccount->parLen) == 0) break;
		}
		SZ_LOG(LOG_WARN,"**AccountSave[%X] PageIndex[%d] len[%d][%d->%d]",
						Addr,pAccount->PageIndex,Maxlen,wlen,rlen);
		pUnit->f.head = GFS_BASIC_BAD;
		SPI_Flash_Write(Addr,(u32*)pUnit,sizeof(DfBalancedAccountUnit));
	}
	//free(pUnit);
	return pAccount->parLen;
}

int BalancedAccountClear(DfBalancedRecord *pAccount)
{
	u32 Addr;
	if(pAccount->PageMax == 0) return -2;
	for(pAccount->PageIndex=0; pAccount->PageIndex<pAccount->PageMax; pAccount->PageIndex++) {		
		if(!(pAccount->PageIndex % pAccount->PageNum)) {
			Addr=GFS_BLOCK_SIZE*(pAccount->blockStart+(pAccount->PageIndex / pAccount->PageNum)) + \
				pAccount->pgSize * (pAccount->PageIndex % pAccount->PageNum);
			SPI_Flash_ERASE_SECTOR(Addr);
		}
	}
	pAccount->PageIndex=0;
	pAccount->count=0;
	//free(pUnit);
	return 0;
}

int BalancedAccountCheck(u16 BlockStart,u16 BlockNum)
{
	for(u16 i=0;i<BlockNum;i++) {
		eFlashCheck head;
		u32 Addr = GFS_BLOCK_SIZE * (BlockStart+i);
		int ret = SPI_Flash_Read(Addr,(u32*)&head,sizeof(head));
		if(ret < 0) return ret;
		if(head.head == GFS_BASIC_DATA && head.pgSize <= GFS_BLOCK_SIZE) {
			return 0;
		}
	}
	return 1;
}

//====================================流水记录 可以查记录===================================




#endif


